#ifndef __BUILDER__
#define __BUILDER__

#include "logger.hpp"

namespace log_p
{
    // 日志器类型
    enum class LoggerType
    {
        LOGGER_SYN, // 同步日志器
        LOGGER_ASYN // 异步日志器
    };
    // 功能：提供对外接口，通过该类完成日志器配件的构造
    // 局部建造者 & 全局建造者
    class BuilderLogger
    {
    public:
        BuilderLogger(const std::string &logger_name, LoggerType tmp,
                      log_p::log_level::values limit_level = log_p::log_level::values::DEBUG)
            : loggertype(tmp), _limit_level(limit_level), _logger_name(logger_name)
        {
        }

        void builder_name(const std::string &str) { _logger_name = str; }
        void builder_formater(const std::string &formatter = "[%d][%p]%T%m%T[%f][%l][%c][%t]%n")
        {
            _formatter_fty = std::shared_ptr<log_p::Formatter>(new log_p::Formatter(formatter));
        } // 我都想重载了，就用正常的

        void builder_level(log_level::values it) { _limit_level = it; }

        template <class SinkBySome, class... Args>
        log_p::LogSink::ptr builder_sink_pool(Args &&...args)
        {
            auto ret = log_p::LogSinkFactory::CreateLogSink<SinkBySome>(std::forward<Args>(args)...);
            _sink_pool.push_back(ret);
            return ret;
        }

        virtual log_p::Logger::ptr build() = 0;

    protected:
        LoggerType loggertype;                       // 日志器落地类型（同步 / 异步）
        std::vector<log_p::LogSink::ptr> _sink_pool; // 落地方向对象数组
        std::string _logger_name;                    // 日志器唯一名称
        log_p::Formatter::ptr _formatter_fty;        // 日志格式化工厂

        log_level::values _limit_level;
    };

    // 派生出建造者类----局部日志器构造者(区别于全局日志器构造者) & 全局日志器构造者(日志器单例模式)
    class LocalBuilderLogger : public BuilderLogger
    {
    public:
        LocalBuilderLogger(const std::string &name, log_p::LoggerType loggertype = log_p::LoggerType::LOGGER_SYN)
            : BuilderLogger(name, loggertype)
        {
        }

        log_p::Logger::ptr build()
        {
            assert(!_logger_name.empty());
            if (_formatter_fty.get() == nullptr)
            {
                builder_formater("");
            }

            if (_sink_pool.size() == 0)
            {
                builder_sink_pool<log_p::CoutSink>();
                builder_sink_pool<log_p::RollFileBySizeSink>(1024 * 1024, "./log/log_by_size/log");
            }

            if (loggertype == LoggerType::LOGGER_SYN)
                return std::make_shared<log_p::SynLogger>(_logger_name, _limit_level, _formatter_fty, _sink_pool);
            if (loggertype == LoggerType::LOGGER_ASYN)
                return std::make_shared<log_p::AsynLogger>(_logger_name, _limit_level, _formatter_fty, _sink_pool);
        }
    };

    // 全局日志器管理类
    // 采用单例模式
    class SingletonBuilderLogger : public BuilderLogger
    {
    public:
        using ptr = std::shared_ptr<SingletonBuilderLogger>;

        // 返回默认日志器
        log_p::Logger::ptr build()
        {
            assert(!_logger_name.empty());
            if (_formatter_fty.get() == nullptr)
            {
                builder_formater();
            }

            if (_sink_pool.size() == 0)
            {
                builder_sink_pool<log_p::CoutSink>();
                builder_sink_pool<log_p::RollFileBySizeSink>(1024 * 1024, "./log/log_by_size/log");
            }

            log_p::Logger::ptr tmp;
            if (loggertype == LoggerType::LOGGER_SYN)
                tmp = std::make_shared<log_p::SynLogger>(_logger_name, _limit_level, _formatter_fty, _sink_pool);
            if (loggertype == LoggerType::LOGGER_ASYN)
                tmp = std::make_shared<log_p::AsynLogger>(_logger_name, _limit_level, _formatter_fty, _sink_pool);

            {
                std::unique_lock<std::mutex>(_tree_mutex);
                _logger_tree.insert({_logger_name, tmp});
            }
            return tmp;
        }

        log_p::Logger::ptr GetRoolLogger()
        {
            return GetLogger(_name);
        }

        // 添加日志器
        log_p::Logger::ptr AddLogger(const std::string &str_name, log_p::LoggerType loggertype = log_p::LoggerType::LOGGER_SYN)
        {
            LocalBuilderLogger it(str_name, loggertype);
            auto tmp = it.build();
            if (tmp == nullptr)
                return nullptr;
            {
                std::unique_lock<std::mutex>(_tree_mutex);
                _logger_tree.insert({str_name, tmp});
            }
            return tmp;
        }

        // 获取具体日志器
        log_p::Logger::ptr GetLogger(const std::string &str)
        {
            if (IsExsit(str))
                return _logger_tree[str];
            return nullptr;
        }

        // 销毁具体日志器
        bool DelLogger(const std::string &str)
        {
            if (IsExsit(str))
            {
                _logger_tree.erase(str);
                return true;
            }
            return false;
        }

        // 检测日志器存在
        bool IsExsit(const std::string &str)
        {
            return _logger_tree.find(str) != _logger_tree.end();
        }

        // 初始化全局日志管理树，设置默认日志器；如果存在则返回已存在默认日志器。
        static ptr GetInstance(const std::string &name = "", log_p::LoggerType loggertype = log_p::LoggerType::LOGGER_SYN)
        {
            if (SBL_PTR == nullptr)
            {
                std::unique_lock<std::mutex> it(sing_mutex);
                if (SBL_PTR == nullptr)
                {
                    SBL_PTR = ptr(new SingletonBuilderLogger(name, loggertype));
                }
            }
            // 也可以使用C++11的新特性，编译器会从编译层，将static 修饰的数据，在未完成构造前，不允许其他线程将阻塞，
            // 阻止进入构造函数，写法如下:
            // static ptr SBL_PTR(new SingletonBuilderLogger(name, loggertype));
            return SBL_PTR;
        }

        SingletonBuilderLogger() = delete;
        SingletonBuilderLogger(const SingletonBuilderLogger &it) = delete;
        SingletonBuilderLogger &operator=(const SingletonBuilderLogger &it) = delete;

    private:
        SingletonBuilderLogger(const std::string &name, log_p::LoggerType loggertype)
            : BuilderLogger(name, loggertype)
        {
            _name = name;
        }

        std::string _name;            // 全局日志器——默认日志器
        static std::mutex sing_mutex; // 全局日志器构造锁
        static ptr SBL_PTR;           // 全局日志器本身

        std::unordered_map<std::string, log_p::Logger::ptr> _logger_tree; // 全局日志器管理树
        std::mutex _tree_mutex;                                           // 管理树锁
    };
    SingletonBuilderLogger::ptr SingletonBuilderLogger::SBL_PTR = nullptr;
    std::mutex SingletonBuilderLogger::sing_mutex;
}

#endif
